// carolsail

import { ENUM_AUDIO_CLIP, ENUM_GAME_MODE, ENUM_GAME_STATUS, ENUM_UI_TYPE } from "../Enum";
import { StaticInstance } from "../StaticInstance";
import { getAngle, random } from "../Utils";
import AudioManager from "../manager/AudioManager";
import DataManager, { GAME_DATA } from "../manager/DataManager";
import ResourceManager from "../manager/ResourceManager";
import AINavigate, { Point } from "../plugins/AINavigate";
import Car from "./Car";

const { ccclass, property } = cc._decorator;

export enum PLAYER_STATE {
    IDLE = 'player_idle',
    MOVE = 'player_move',
    WAIT = 'player_wait',
}

@ccclass
export default class Player extends cc.Component {

    anim: cc.Animation = null
    colorIndex: number = 0
    posX: number = -1
    posY: number = -1
    state: PLAYER_STATE = PLAYER_STATE.IDLE
    targetMarkKey: number = -1

    init(x: number, y: number, colorIndex: number) {
        this.anim = this.node.getComponent(cc.Animation)
        this.posX = x
        this.posY = y
        this.colorIndex = colorIndex
        this.setColor(colorIndex)
        this.state = PLAYER_STATE.IDLE
        this.setPos(x, y)
        if (!this.node.hasEventListener('touchstart')) this.node.on('touchstart', this.onTouchStart, this)
        // 定时渲染表情
        this.schedule(() => {
            const rand = random(1, 20)
            if (rand >= 15) this.rendorEmote()
        }, 3)
    }

    appendInit() {
        this.anim = this.node.getComponent(cc.Animation)
        this.state = PLAYER_STATE.IDLE
        if (!this.node.hasEventListener('touchstart')) this.node.on('touchstart', this.onTouchStart, this)
    }

    setColor(colorIndex: number) {
        this.colorIndex = colorIndex
        const color = new cc.Color().fromHEX(GAME_DATA.COLORS[colorIndex])
        this.node.children.forEach(child => {
            if (child.name != 'emote') child.color = color
        })
    }

    setPos(x: number, y: number) {
        const board = DataManager.instance.mapBoards.get(x + y * GAME_DATA.BOARD_SIZE)
        this.node.setPosition(board.getPosition())
        this.node.scale = 0.5
        cc.tween(this.node).to(0.2, { scale: 1 }).start()
    }

    setPosByMove(x: number, y: number, cb?: () => void) {
        this.posX = x
        this.posY = y
        const board = DataManager.instance.mapBoards.get(x + y * GAME_DATA.BOARD_SIZE)
        const mpos = board.getPosition()
        cc.tween(this.node).delay(0.2).call(() => {
            this.node.opacity = 255
        }).to(0.1, { position: cc.v3(mpos.x, mpos.y, 0) }).call(() => {
            cb && cb()
        }).start()
    }

    rendorEmote() {
        const emote = this.node.getChildByName('emote')
        if (this.state == PLAYER_STATE.IDLE) {
            if (!emote.active) {
                emote.getComponent(cc.Sprite).spriteFrame = ResourceManager.instance.getSprite(`emote_${random(1, 27)}`)
                emote.active = true
            }
        } else {
            if (emote.active) {
                emote.active = false
            }
        }
    }

    onTouchStart() {
        // console.log('x:', this.posX, 'y:', this.posY)
        let route = null
        if (this.state != PLAYER_STATE.IDLE) return
        if (DataManager.instance.isCovering) return
        if (DataManager.instance.status == ENUM_GAME_STATUS.UNRUNING) return
        if (DataManager.instance.mapTargetMark.size >= DataManager.instance.targetMarkLimit) return

        // 换位技能
        if (StaticInstance.uiManager.getMainSkillTip()) {
            if (DataManager.instance.skillPlayerComp.length < 2) {
                DataManager.instance.skillPlayerComp.push(this)
            }
            const len = DataManager.instance.skillPlayerComp.length
            if (len == 1) {
                const board = DataManager.instance.mapBoards.get(this.posX + this.posY * GAME_DATA.BOARD_SIZE)
                DataManager.instance.skillBoardNode = board
                DataManager.instance.skillBoardColor = '#' + DataManager.instance.skillBoardNode.color.toHEX()
                board.color = new cc.Color().fromHEX('#FF789F')
            }
            if (len == 2) {
                AudioManager.instance.playSound(ENUM_AUDIO_CLIP.SKILL_EXCHANGE)
                const tempColorIndex = DataManager.instance.skillPlayerComp[0].colorIndex
                DataManager.instance.skillPlayerComp[0].setColor(DataManager.instance.skillPlayerComp[1].colorIndex)
                DataManager.instance.skillPlayerComp[1].setColor(tempColorIndex)
                DataManager.instance.skillBoardNode.color = new cc.Color().fromHEX(DataManager.instance.skillBoardColor)
                DataManager.instance.skillPlayerComp = []
                DataManager.instance.skillBoardNode = null
                DataManager.instance.skillBoardColor = ''
                StaticInstance.uiManager.setMainSkillTip(false)
            }
            return
        }

        const board = DataManager.instance.mapBoards.get(this.posX + this.posY * GAME_DATA.BOARD_SIZE)
        if (board.color.getB() == 255) {
            AudioManager.instance.playSound(ENUM_AUDIO_CLIP.CLICK_NONE)
            return
        }
        if (!DataManager.instance.mapTargetMark.has(0)) {
            this.targetMarkKey = 0
        } else if (!DataManager.instance.mapTargetMark.has(1)) {
            this.targetMarkKey = 1
        } else if (!DataManager.instance.mapTargetMark.has(2)) {
            this.targetMarkKey = 2
        } else if (!DataManager.instance.mapTargetMark.has(3)) {
            this.targetMarkKey = 3
        } else if (!DataManager.instance.mapTargetMark.has(4)) {
            this.targetMarkKey = 4
        } else if (!DataManager.instance.mapTargetMark.has(5)) {
            this.targetMarkKey = 5
        }
        DataManager.instance.mapTargetMark.set(this.targetMarkKey, this)
        route = this.checkMove(this.targetMarkKey)
        if (route.length) {
            AudioManager.instance.playSound(ENUM_AUDIO_CLIP.CLICK_ITEM)
            this.state = PLAYER_STATE.MOVE
            this.anim.play(this.state)
            // 需要补位
            if (StaticInstance.gameManager.getLevelComp().playerColorIndexArr.length) {
                DataManager.instance.isCovering = true
                StaticInstance.gameManager.getLevelComp().onPlayerCover([{ x: this.posX, y: this.posY }])
            } else {
                // 更新map points
                StaticInstance.gameManager.getLevelComp().resetMapPoints(this.posX, this.posY)
            }
            this.setMove(route)
        }
    }

    checkMove(x: number = 0, y: number = 0) {
        let route: Point[] = []
        const points = new Map(DataManager.instance.mapPoints)
        points.set(this.posX + this.posY * GAME_DATA.BOARD_SIZE, new Point(this.posX, this.posY))
        const point_start = new Point(this.posX, this.posY)
        const point_end = new Point(x, y)
        route = AINavigate.getRoute(point_start, point_end, points, new cc.Size(GAME_DATA.BOARD_SIZE, GAME_DATA.BOARD_SIZE))
        return route
    }

    // 移动到候车点
    setMove(routeArr: Point[]) {
        const actions: cc.FiniteTimeAction[] = []
        let currentRoute = null
        for (let i = 0; i < routeArr.length; i++) {
            const route = routeArr[i]
            const board = DataManager.instance.mapBoards.get(route.x + route.y * GAME_DATA.BOARD_SIZE)
            const act1 = cc.moveTo(0.2, board.x, board.y)
            // 转向
            let act2 = cc.rotateTo(0.2, 0)
            let angle = 0
            if (currentRoute) {
                // console.log(currentRoute.x, currentRoute.y, route.x, route.y)
                if (currentRoute.x == route.x && currentRoute.y > route.y) {
                    act2 = cc.rotateTo(0.2, 0)
                    angle = 0
                } else if (currentRoute.x > route.x && currentRoute.y == route.y) {
                    act2 = cc.rotateTo(0.2, -90)
                    angle = -90
                } else if (currentRoute.x < route.x && currentRoute.y == route.y) {
                    act2 = cc.rotateTo(0.2, 90)
                    angle = 90
                }
            }
            actions.push(cc.spawn(act1, act2))
            // 纠正朝向
            if (i == routeArr.length - 1 && angle != 0) {
                actions.push(cc.rotateTo(0.1, 0))
            }
            currentRoute = route
        }
        if (actions.length) {
            this.rendorEmote()
            let act = actions[0]
            if (actions.length > 1) {
                act = cc.sequence(actions)
            }
            cc.tween(this.node).then(act).call(() => {
                this.state = PLAYER_STATE.WAIT
                const lastRoute = routeArr[routeArr.length - 1]
                this.posX = lastRoute.x
                this.posY = lastRoute.y
                // 移动上车
                this.setMoveCar()
            }).start()
        }
    }

    // 移动上车
    setMoveCar(isMulti: boolean = false) {
        const carNode = StaticInstance.gameManager.getLevelComp().getTargetCar()
        if (carNode) {
            const carComp = carNode.getComponent(Car)
            if (carComp.colorIndex == this.colorIndex && carComp.playerKeyArr.length < GAME_DATA.COMBINE) {
                this.rendorEmote()
                DataManager.instance.levelPlayerClear += 1
                StaticInstance.uiManager.setMainPlayerNum()
                if (!isMulti) AudioManager.instance.playSound(ENUM_AUDIO_CLIP.CAR_OPEN)
                carComp.playerKeyArr.push(this.targetMarkKey)
                DataManager.instance.mapTargetMark.delete(this.targetMarkKey)
                // 上车
                const wpos = carNode.convertToWorldSpaceAR(cc.v2(0, 0))
                const pos = this.node.parent.convertToNodeSpaceAR(wpos)
                let angle = getAngle(this.node.getPosition(), pos)
                if (this.targetMarkKey <= 2) angle = -angle
                const scale = 0.8
                // 上车过程状态更改
                this.state = PLAYER_STATE.MOVE
                cc.tween(this.node).to(0.5, { position: cc.v3(pos.x, pos.y, 0), angle, scale }).call(() => {
                    this.state = PLAYER_STATE.WAIT
                    this.node.removeFromParent()
                    carComp.rendorPlayer(angle)
                    // 车离站
                    if (carComp.playerKeyArr.length >= GAME_DATA.COMBINE) {
                        if (carComp.playerKeyArr[carComp.playerKeyArr.length - 1] == this.targetMarkKey) {
                            carComp.setMove(GAME_DATA.CAR_POSX[3], GAME_DATA.CAR_POSX[4])
                        }
                    }
                }).start()
            } else {
                // 判定游戏失败
                if (DataManager.instance.mapTargetMark.size >= DataManager.instance.targetMarkLimit) {
                    const arrTargetMark = Array.from(DataManager.instance.mapTargetMark.keys())
                    const lastTarget = arrTargetMark[arrTargetMark.length - 1]
                    if (this.targetMarkKey == lastTarget) {
                        let isCarColor = false
                        DataManager.instance.mapTargetMark.forEach(playerComp => {
                            if (playerComp.colorIndex == carComp.colorIndex) isCarColor = true
                        })
                        // console.log('游戏结束')
                        if (DataManager.instance.mode == ENUM_GAME_MODE.NORMAL) {
                            !isCarColor && StaticInstance.gameManager.onGameOver(ENUM_UI_TYPE.LOSE)
                        } else {
                            !isCarColor && StaticInstance.gameManager.onGameOverPk(false)
                        }
                    }
                }
            }
        }
    }
}
